home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / uux789 / uud.c < prev    next >
C/C++ Source or Header  |  1993-07-08  |  12KB  |  573 lines

  1. /*
  2.  * Uud -- decode a uuencoded file back to binary form.
  3.  *
  4.  * From the Berkeley original, modified by MSD, RDR, JPHD & WLS.
  5.  * The Atari GEMDOS version compiled with MWC 2.x.
  6.  * The MSDOS version with TurboC.
  7.  * The Unix version with cc.
  8.  * this version is made: 25 Nov 1988.
  9.  */
  10.  
  11. /*
  12.  * Be sure to have the proper symbol at this point. (GEMDOS, MSDOS, UNIX...)
  13.  */
  14. /*
  15. #ifndef GEMDOS
  16. #define GEMDOS 1
  17. #endif
  18.  */
  19. #ifndef UNIX
  20. #define UNIX 1
  21. #endif
  22. /*
  23. #ifndef MSDOS
  24. #define MSDOS 1
  25. #endif
  26.  */
  27.  
  28. #ifdef GEMDOS
  29. #define SYSNAME "gemdos"
  30. #define SMALL 1
  31. #endif
  32. #ifdef MSDOS
  33. #define SYSNAME "msdos"
  34. #define SMALL 1
  35. #endif
  36. #ifdef UNIX
  37. #define SYSNAME "unix"
  38. #endif
  39.  
  40. #include <stdio.h>
  41.  
  42. #ifdef GEMDOS
  43. #include <osbind.h>
  44. #define Error(n)  { Bconin(2); exit(n); }
  45. #define WRITE      "wb"
  46. #else
  47. #define Error(n)  exit(n)
  48. #define WRITE      "w"
  49. #endif
  50.  
  51. #define loop    while (1)
  52.  
  53. extern FILE *fopen();
  54. extern char *strcpy();
  55. extern char *strcat();
  56.  
  57. char *getnword();
  58.  
  59. #define MAXCHAR 256
  60. #define LINELEN 256
  61. #define FILELEN 64
  62. #define NORMLEN 60    /* allows for 80 encoded chars per line */
  63.  
  64. #define SEQMAX 'z'
  65. #define SEQMIN 'a'
  66. char seqc;
  67. int first, secnd, check, numl;
  68.  
  69. FILE *in, *out;
  70. char *pos;
  71. char ifname[FILELEN], ofname[FILELEN];
  72. char *source = NULL, *target = NULL;
  73. char blank, part = '\0';
  74. int partn, lens;
  75. int debug = 0, nochk = 0, onedone = 0;
  76. int chtbl[MAXCHAR], cdlen[NORMLEN + 3];
  77.  
  78. main(argc, argv) int argc; char *argv[];
  79. {
  80.     int mode;
  81.     register int i, j;
  82.     char *curarg;
  83.     char dest[FILELEN], buf[LINELEN];
  84.  
  85.     if (argc < 2) {
  86.         format("Almost foolproof uudecode v3.4 (%s) 25-Nov-88\n",
  87.             SYSNAME);
  88.         format("\n");
  89.         format("Usage: uud [-n] [-d] [-s dir] [-t dir] input-file\n");
  90.         format("\n");
  91.         format("Option: -n -> No line sequence check\n");
  92.         format("Option: -d -> Debug/verbose mode\n");
  93.         format("Option: -s + Source directory for all input files\n");
  94.         format("  (MUST be terminated by directory separator)\n");
  95.         format("Option: -t + Target directory for all output files\n");
  96.         format("  (MUST be terminated by directory separator)\n");
  97.         format("If input-file is - then stdin is used as input-file\n");
  98.         Error(1);
  99.     }
  100.  
  101.     curarg = argv[1];
  102.     
  103.     while (curarg[0] == '-') {
  104.         if (((curarg[1] == 'd') || (curarg[1] == 'D')) &&
  105.             (curarg[2] == '\0')) {
  106.             debug = 1;
  107.         } else if (((curarg[1] == 'n') || (curarg[1] == 'N')) &&
  108.                (curarg[2] == '\0')) {
  109.             nochk = 1;
  110.         } else if (((curarg[1] == 't') || (curarg[1] == 'T')) &&
  111.                (curarg[2] == '\0')) {
  112.             argv++;
  113.             argc--;
  114.             if (argc < 2) {
  115.                 format("uud: Missing target directory.\n");
  116.                 Error(15);
  117.             }
  118.             target = argv[1];
  119.             if (debug)
  120.                 format("Target dir = %s\n",target);
  121.         } else if (((curarg[1] == 's') || (curarg[1] == 'S')) &&
  122.                (curarg[2] == '\0')) {
  123.             argv++;
  124.             argc--;
  125.             if (argc < 2) {
  126.                 format("uud: Missing source directory.\n");
  127.                 Error(15);
  128.             }
  129.             source = argv[1];
  130.             if (debug)
  131.                 format("Source dir = %s\n",source);
  132.         } else if (curarg[1] != '\0') {
  133.             format("uud: Unknown option <%s>\n", curarg);
  134.             Error(15);
  135.         } else
  136.             break;
  137.         argv++;
  138.         argc--;
  139.         if (argc < 2) {
  140.             format("uud: Missing file name.\n");
  141.             Error(15);
  142.         }
  143.         curarg = argv[1];
  144.     }
  145.  
  146.     if ((curarg[0] == '-') && (curarg[1] == '\0')) {
  147.         in = stdin;
  148.         strcpy(ifname, "<stdin>");
  149.     } else {
  150.         if (source != NULL) {
  151.             strcpy(ifname, source);
  152.             strcat(ifname, curarg);
  153.         } else
  154.             strcpy(ifname, curarg);
  155.         if ((in = fopen(ifname, "r")) == NULL) {
  156.             format("uud: Can't open %s\n", ifname);
  157.             Error(2);
  158.         }
  159.         numl = 0;
  160.     }
  161.  
  162. /*
  163.  * Set up the default translation table.
  164.  */
  165.     for (i = 0; i < ' '; i++) chtbl[i] = -1;
  166.     for (i = ' ', j = 0; i < ' ' + 64; i++, j++) chtbl[i] = j;
  167.     for (i = ' ' + 64; i < MAXCHAR; i++) chtbl[i] = -1;
  168.     chtbl['`'] = chtbl[' '];    /* common mutation */
  169.     chtbl['~'] = chtbl['^'];    /* an other common mutation */
  170.     blank = ' ';
  171. /*
  172.  * set up the line length table, to avoid computing lotsa * and / ...
  173.  */
  174.     cdlen[0] = 1;
  175.     for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4)
  176.         cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j));
  177. /*
  178.  * search for header or translation table line.
  179.  */
  180.     loop {    /* master loop for multiple decodes in one file */
  181.         partn = 'a';
  182.         loop {
  183.             if (fgets(buf, sizeof buf, in) == NULL) {
  184.                 if (onedone) {
  185.                     if (debug) format("End of file.\n");
  186.                     exit(0);
  187.                 } else {
  188.                     format("uud: No begin line.\n");
  189.                     Error(3);
  190.                 }
  191.             }
  192.             numl++;
  193.             if (strncmp(buf, "table", 5) == 0) {
  194.                 gettable();
  195.                 continue;
  196.             }
  197.             if (strncmp(buf, "begin", 5) == 0) {
  198.                 break;
  199.             }
  200.         }
  201.         lens = strlen(buf);
  202.         if (lens) buf[--lens] = '\0';
  203. #ifdef SMALL
  204.         if ((pos = getnword(buf, 3))) {
  205.             strcpy(dest, pos);
  206.         } else
  207. #else
  208.         if(sscanf(buf,"begin%o%s", &mode, dest) != 2)
  209. #endif
  210.         {
  211.             format("uud: Missing filename in begin line.\n");
  212.             Error(10);
  213.         }
  214.  
  215.         if (target != NULL) {
  216.             strcpy(ofname, target);
  217.             strcat(ofname, dest);
  218.         } else
  219.             strcpy(ofname, dest);
  220.  
  221.         if((out = fopen(ofname, WRITE)) == NULL) {
  222.             format("uud: Cannot open output file: %s\n", ofname);
  223.             Error(4);
  224.         }
  225.         if (debug) format("Begin uudecoding: %s\n", ofname);
  226.         seqc = SEQMAX;
  227.         check = nochk ? 0 : 1;
  228.         first = 1;
  229.         secnd = 0;
  230.         decode();
  231.         fclose(out);
  232. #ifdef UNIX
  233.         chmod(ofname, mode);
  234. #endif
  235.         onedone = 1;
  236.         if (debug) format("End uudecoding: %s\n", ofname);
  237.     }    /* master loop for multiple decodes in one file */
  238. }
  239.  
  240. /*
  241.  * Bring back a pointer to the start of the nth word.
  242.  */
  243. char *getnword(str, n) register char *str; register int n;
  244. {
  245.     while((*str == '\t') || (*str == ' ')) str++;
  246.     if (! *str) return NULL;
  247.     while(--n) {
  248.         while ((*str != '\t') && (*str != ' ') && (*str)) str++;
  249.         if (! *str) return NULL;
  250.         while((*str == '\t') || (*str == ' ')) str++;
  251.         if (! *str) return NULL;
  252.     }
  253.     return str;
  254. }
  255.  
  256. /*
  257.  * Install the table in memory for later use.
  258.  */
  259. gettable()
  260. {
  261.     char buf[LINELEN];
  262.     register int c, n = 0;
  263.     register char *cpt;
  264.  
  265.     for (c = 0; c <= MAXCHAR; c++) chtbl[c] = -1;
  266.  
  267. again:    if (fgets(buf, sizeof buf, in) == NULL) {
  268.         format("uud: EOF while in translation table.\n");
  269.         Error(5);
  270.     }
  271.     numl++;
  272.     if (strncmp(buf, "begin", 5) == 0) {
  273.         format("uud: Incomplete translation table.\n");
  274.         Error(6);
  275.     }
  276.     cpt = buf + strlen(buf) - 1;
  277.     *cpt = ' ';
  278.     while (*(cpt) == ' ') {
  279.         *cpt = 0;
  280.         cpt--;
  281.     }
  282.     cpt = buf;
  283.     while (c = *cpt) {
  284.         if (chtbl[c] != -1) {
  285.             format("uud: Duplicate char in translation table.\n");
  286.             Error(7);
  287.         }
  288.         if (n == 0) blank = c;
  289.         chtbl[c] = n++;
  290.         if (n >= 64) return;
  291.         cpt++;
  292.     }
  293.     goto again;
  294. }
  295.  
  296. /*
  297.  * copy from in to out, decoding as you go along.
  298.  */
  299.  
  300. decode()
  301. {
  302.     char buf[LINELEN], outl[LINELEN];
  303.     register char *bp, *ut;
  304.     register int *trtbl = chtbl;
  305.     register int n, c, rlen;
  306.     register unsigned int len;
  307.  
  308.     loop {
  309.         if (fgets(buf, sizeof buf, in) == NULL) {
  310.             format("uud: EOF before end.\n");
  311.             fclose(out);
  312.             Error(8);
  313.         }
  314.         numl++;
  315.         len = strlen(buf);
  316.         if (len) buf[--len] = '\0';
  317. /*
  318.  * Is it an unprotected empty line before the end line ?
  319.  */
  320.         if (len == 0) continue;
  321. /*
  322.  * Get the binary line length.
  323.  */
  324.         n = trtbl[*buf];
  325.         if (n >= 0) goto decod;
  326. /*
  327.  * end of uuencoded file ?
  328.  */
  329.         if (strncmp(buf, "end", 3) == 0) return;
  330. /*
  331.  * end of current file ? : get next one.
  332.  */
  333.         if (strncmp(buf, "include", 7) == 0) {
  334.             getfile(buf);
  335.             continue;
  336.         }
  337.         format("uud: Bad prefix line %d in file: %s\n",numl, ifname);
  338.         if (debug) format("Bad line =%s\n",buf);
  339.         Error(11);
  340. /*
  341.  * Sequence checking ?
  342.  */
  343. decod:        rlen = cdlen[n];
  344. /*
  345.  * Is it the empty line before the end line ?
  346.  */
  347.         if (n == 0) continue;
  348. /*
  349.  * Pad with blanks.
  350.  */
  351.         for (bp = &buf[c = len];
  352.             c < rlen; c++, bp++) *bp = blank;
  353. /*
  354.  * Verify if asked for.
  355.  */
  356.         if (debug) {
  357.             for (len = 0, bp = buf; len < rlen; len++) {
  358.                 if (trtbl[*bp] < 0) {
  359.                     format(
  360.     "Non uuencoded char <%c>, line %d in file: %s\n", *bp, numl, ifname);
  361.                     format("Bad line =%s\n",buf);
  362.                     Error(16);
  363.                 }
  364.                 bp++;
  365.             }
  366.         }
  367. /*
  368.  * All this just to check for uuencodes that append a 'z' to each line....
  369.  */
  370.         if (secnd && check) {
  371.             secnd = 0;
  372.             if (buf[rlen] == SEQMAX) {
  373.                 check = 0;
  374.                 if (debug) format("Sequence check turned off (2).\n");
  375.             } else
  376.                 if (debug) format("Sequence check on (2).\n");
  377.         } else if (first && check) {
  378.             first = 0;
  379.             secnd = 1;
  380.             if (buf[rlen] != SEQMAX) {
  381.                 check = 0;
  382.                 if (debug) format("No sequence check (1).\n");
  383.             } else
  384.                 if (debug) format("Sequence check on (1).\n");
  385.         }
  386. /*
  387.  * There we check.
  388.  */
  389.         if (check) {
  390.             if (buf[rlen] != seqc) {
  391.                 format("uud: Wrong sequence line %d in %s\n",
  392.                     numl, ifname);
  393.                 if (debug)
  394.                     format(
  395.     "Sequence char is <%c> instead of <%c>.\n", buf[rlen], seqc);
  396.                 Error(18);
  397.             }
  398.             seqc--;
  399.             if (seqc < SEQMIN) seqc = SEQMAX;
  400.         }
  401. /*
  402.  * output a group of 3 bytes (4 input characters).
  403.  * the input chars are pointed to by p, they are to
  404.  * be output to file f.n is used to tell us not to
  405.  * output all of them at the end of the file.
  406.  */
  407.         ut = outl;
  408.         len = n;
  409.         bp = &buf[1];
  410.         while (n > 0) {
  411.             *(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4;
  412.             n--;
  413.             if (n) {
  414.                 *(ut++) = (trtbl[bp[1]] << 4) |
  415.                       (trtbl[bp[2]] >> 2);
  416.                 n--;
  417.             }
  418.             if (n) {
  419.                 *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]];
  420.                 n--;
  421.             }
  422.             bp += 4;
  423.         }
  424.         if ((n = fwrite(outl, 1, len, out)) <= 0) {
  425.             format("uud: Error on writing decoded file.\n");
  426.             Error(18);
  427.         }
  428.     }
  429. }
  430.  
  431. /*
  432.  * Find the next needed file, if existing, otherwise try further
  433.  * on next file.
  434.  */
  435. getfile(buf) register char *buf;
  436. {
  437.     if ((pos = getnword(buf, 2)) == NULL) {
  438.         format("uud: Missing include file name.\n");
  439.         Error(17);
  440.     } else
  441.         if (source != NULL) {
  442.             strcpy(ifname, source);
  443.             strcat(ifname, pos);
  444.         } else
  445.             strcpy(ifname, pos);
  446. #ifdef GEMDOS
  447.     if (Fattrib(ifname, 0, 0) < 0)
  448. #else
  449.     if (access(ifname, 04))
  450. #endif
  451.     {
  452.         if (debug) {
  453.             format("Cant find: %s\n", ifname);
  454.             format("Continuing to read same file.\n");
  455.         }
  456.     }
  457.     else {
  458.         if (freopen(ifname, "r", in) == in) {
  459.             numl = 0;
  460.             if (debug) 
  461.                 format("Reading next section from: %s\n", ifname);
  462.         } else {
  463.             format("uud: Freopen abort: %s\n", ifname);
  464.             Error(9);
  465.         }
  466.     }
  467.     loop {
  468.         if (fgets(buf, LINELEN, in) == NULL) {
  469.             format("uud: No begin line after include: %s\n", ifname);
  470.             Error(12);
  471.         }
  472.         numl++;
  473.         if (strncmp(buf, "table", 5) == 0) {
  474.             gettable();
  475.             continue;
  476.         }
  477.         if (strncmp(buf, "begin", 5) == 0) break;
  478.     }
  479.     lens = strlen(buf);
  480.     if (lens) buf[--lens] = '\0';
  481. /*
  482.  * Check the part suffix.
  483.  */
  484.     if ((pos = getnword(buf, 3)) == NULL ) {
  485.         format("uud: Missing part name, in included file: %s\n", ifname);
  486.         Error(13);
  487.     } else {
  488.         part = *pos;
  489.         partn++;
  490.         if (partn > 'z') partn = 'a';
  491.         if (part != partn) {
  492.             format("uud: Part suffix mismatch: <%c> instead of <%c>.\n",
  493.                 part, partn);
  494.             Error(14);
  495.         }
  496.         if (debug) format("Reading part %c\n", *pos);
  497.     }
  498. }
  499.  
  500. /*
  501.  * Printf style formatting. (Borrowed from MicroEmacs by Dave Conroy.) 
  502.  * A lot smaller than the full fledged printf.
  503.  */
  504. /* VARARGS1 */
  505. format(fp, args) char *fp;
  506. {
  507.     doprnt(fp, (char *)&args);
  508. }
  509.  
  510. doprnt(fp, ap)
  511. register char    *fp;
  512. register char    *ap;
  513. {
  514.     register int    c, k;
  515.     register char    *s;
  516.  
  517.     while ((c = *fp++) != '\0') {
  518.         if (c != '%')
  519.             outc(c);
  520.         else {
  521.             c = *fp++;
  522.             switch (c) {
  523.             case 'd':
  524.                 puti(*(int *)ap, 10);
  525.                 ap += sizeof(int);
  526.                 break;
  527.  
  528.             case 's':
  529.                 s = *(char **)ap;
  530.                 while ((k = *s++) != '\0')
  531.                     outc(k);
  532.                 ap += sizeof(char *);
  533.                 break;
  534.  
  535.             case 'c':
  536.                 outc(*(int *)ap);
  537.                 ap += sizeof(int);
  538.                 break;
  539.  
  540.             default:
  541.                 outc(c);
  542.             }
  543.         }
  544.     }
  545. }
  546.  
  547. /*
  548.  * Put integer, in radix "r".
  549.  */
  550. puti(i, r)
  551. register unsigned int    i;
  552. register unsigned int    r;
  553. {
  554.     register unsigned int    q, s;
  555.  
  556.     if ((q = i / r) != 0)
  557.         puti(q, r);
  558.     s = i % r;
  559.     if (s <= 9)
  560.         outc(s + '0');
  561.     else
  562.         outc(s - 10 + 'A');
  563. }
  564. outc(c) register char c;
  565. {
  566. #ifdef GEMDOS
  567.     if (c == '\n') Bconout(2, '\r');
  568.     Bconout(2, c);
  569. #else
  570.     putchar(c);
  571. #endif
  572. }
  573.